const { ValidationError, DatabaseError, TimeoutError } = require('sequelize');
const { logger } = require('../utils/logger');
const config = require('../config');

class AppError extends Error {
  constructor(statusCode, message, errorCode = null) {
    super(message);
    this.statusCode = statusCode;
    this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
    this.errorCode = errorCode;
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

const handleSequelizeError = (err) => {
  if (err instanceof ValidationError) {
    const message = err.errors.map(e => e.message).join('; ');
    return new AppError(400, message, 'VALIDATION_ERROR');
  }
  if (err instanceof DatabaseError) {
    logger.error('Database Error:', err);
    return new AppError(500, '数据库操作失败', 'DATABASE_ERROR');
  }
  if (err instanceof TimeoutError) {
    logger.error('Database Timeout:', err);
    return new AppError(408, '数据库操作超时', 'DATABASE_TIMEOUT');
  }
  return err;
};

const handleJWTError = (err) => {
  if (err.name === 'JsonWebTokenError') {
    return new AppError(401, '无效的令牌', 'INVALID_TOKEN');
  }
  if (err.name === 'TokenExpiredError') {
    return new AppError(401, '令牌已过期', 'TOKEN_EXPIRED');
  }
  return err;
};

const handleValidationError = (err) => {
  if (err.name === 'ValidationError') {
    const errors = Object.values(err.errors).map(e => e.message);
    return new AppError(400, `验证错误: ${errors.join('. ')}`, 'VALIDATION_ERROR');
  }
  return err;
};

const handleMulterError = (err) => {
  if (err.name === 'MulterError') {
    switch (err.code) {
      case 'LIMIT_FILE_SIZE':
        return new AppError(400, '文件大小超过限制', 'FILE_TOO_LARGE');
      case 'LIMIT_FILE_COUNT':
        return new AppError(400, '文件数量超过限制', 'TOO_MANY_FILES');
      case 'LIMIT_UNEXPECTED_FILE':
        return new AppError(400, '未预期的文件类型', 'INVALID_FILE_TYPE');
      default:
        return new AppError(400, '文件上传失败', 'FILE_UPLOAD_ERROR');
    }
  }
  return err;
};

const errorHandler = async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    let error = err;

    // 处理特定类型的错误
    error = handleSequelizeError(error);
    error = handleJWTError(error);
    error = handleValidationError(error);
    error = handleMulterError(error);

    // 如果不是 AppError 实例，转换为通用错误
    if (!(error instanceof AppError)) {
      logger.error('Unhandled Error:', error);
      error = new AppError(
        500,
        config.server.env === 'production' ? '服务器内部错误' : error.message,
        'INTERNAL_SERVER_ERROR'
      );
    }

    // 记录错误日志
    if (error.statusCode >= 500) {
      logger.error('Server Error:', {
        statusCode: error.statusCode,
        message: error.message,
        errorCode: error.errorCode,
        stack: error.stack,
        path: ctx.path,
        method: ctx.method,
        ip: ctx.ip,
        userId: ctx.state.user ? ctx.state.user.id : null
      });
    } else {
      logger.warn('Client Error:', {
        statusCode: error.statusCode,
        message: error.message,
        errorCode: error.errorCode,
        path: ctx.path,
        method: ctx.method,
        ip: ctx.ip,
        userId: ctx.state.user ? ctx.state.user.id : null
      });
    }

    // 设置响应
    ctx.status = error.statusCode;
    ctx.body = {
      status: error.status,
      error: {
        code: error.errorCode,
        message: error.message
      },
      ...(config.server.env === 'development' && {
        stack: error.stack,
        details: error.details
      })
    };

    // 触发错误事件以便进一步处理（如通知、监控等）
    ctx.app.emit('error', error, ctx);
  }
};

// 未捕获的 Promise 拒绝处理
process.on('unhandledRejection', (err) => {
  logger.error('Unhandled Rejection:', err);
  // 在开发环境下抛出错误以便调试
  if (config.server.env === 'development') {
    throw err;
  }
});

// 未捕获的异常处理
process.on('uncaughtException', (err) => {
  logger.error('Uncaught Exception:', err);
  // 记录错误并优雅退出
  process.exit(1);
});

module.exports = {
  AppError,
  errorHandler
}; 